/*
SteelNzb
Copyright (C) 2008  Wessel v. Staal

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "conf.h"
#include "filesys.h"
#include "manager.h"
#include "global.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <libxml/xmlreader.h>

#ifdef WINCE /* wince does not have gui, generate messageboxes on error */
#undef PRINTERROR
#define PRINTERROR(x) MessageBox(NULL, L##x, L"SteelNzbMobile", MB_ICONERROR | MB_OK)
#endif

#if defined(WIN32) || defined(WINCE)
#include <winsock2.h>
#include <windows.h>
#define stricmp _stricmp
#ifndef WINCE
#include <direct.h>
#include <crtdbg.h>
#endif
#else
#include <unistd.h>
#define stricmp strcasecmp
#endif

#define DOWNLOAD_PATH "download"
#define NZB_PATH "nzb/"

void* createmanagerState(void* cfg);
int startNzbCheck(void* managerstate, char* dir);
int main();

#ifdef WINCE
/* wince requires winmain entry point */
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
	return main();
}
#endif

int main()
{
	void* cfg = NULL;
	void* managerstate = NULL;
	config_entry* nzbDir = NULL;
	char* path = "steelnzb.conf";
	

#ifdef WINCE
	TCHAR pathW[MAX_PATH];
#endif

	#ifdef WIN32
		WSADATA wData;
		WSAStartup(MAKEWORD(1,1), &wData);
#ifndef WINCE
		_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
	//	_CrtSetBreakAlloc(105);
	#endif

	printf("********************** SteelNzb **********************\n");
	printf("Usenet leecher\n");
	printf("Author: Wessel v. Staal\n");
	printf("Version: 1.0\n");
	printf("**********************          **********************\n");

	printf("Initializing xml parser..");

	xmlInitParser();

	printf("OK\n");

	printf("Reading configuration..");

#ifdef WINCE
	GetModuleFileName(NULL, pathW, MAX_PATH);
	
	if ( (path = malloc(MAX_PATH)) == NULL )
	{
		PRINTERROR("Main");
		exit(1);
	}

	if ( WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, MAX_PATH, NULL, NULL) == 0 )
	{
		PRINTERROR("Main");
		exit(1);
	}
	else
	{
		char* slash = strrchr(path, '\\');
		*slash = 0;
		strcat(path, "\\steelnzb.conf");
	}
	
#endif
	if ( (cfg = config_readFile(path)) == NULL )
	{
		PRINTERROR("ConfigFile missing");
		exit(1);
	}
#ifdef WINCE
free(path);
#endif
	printf("OK\n");

	printf("Initializing...");

	if ( (managerstate = createmanagerState(cfg)) == NULL )
	{
		PRINTERROR("Main::Could not initialize manager");
		exit(1);
	}

	printf("OK\n");

	if ( (nzbDir = config_findEntry(cfg, "nzbDir")) == NULL )
	{
		PRINTERROR("Main::Could not find config entry nzbDir");
		exit(1);
	}

	
	if ( !filesys_itemExists(nzbDir->value) )
	{
		PRINTERROR("Main::Nzb directory does not exist");
		exit(1);
	}

	printf("Started checking for nzb files in '%s'\n", nzbDir->value);

#ifdef WINCE
MessageBox(NULL, L"Started SteelNzbMobile. You will need to use remote control in order to shut down this application.", 
		   L"SteelNzbMobile", MB_ICONINFORMATION | MB_OK);
#endif

	startNzbCheck(managerstate, nzbDir->value);

	getc(stdin);

	config_free(cfg);
	manager_freeState(managerstate);

	xmlCleanupParser();

#ifdef WIN32
	WSACleanup();
	#ifndef WINCE
	_CrtDumpMemoryLeaks();
#endif
#endif

	return 0;
}

/**
	Creates manager, reads from configuration
	@param cfg Pointer to the config data
	@returns pointer to manager state
*/
void* createmanagerState(void* cfg)
{
	config_entry* max_threads = NULL;
	config_entry* max_connect_tries = NULL;
	config_entry* max_article_tries = NULL;
	config_entry* username = NULL;
	config_entry* password = NULL;
	config_entry* host = NULL;
	config_entry* port = NULL;
	config_entry* enable_yenc = NULL;
	config_entry* enable_remote = NULL;
	config_entry* enable_combine = NULL;
	config_entry* remote_port= NULL;
	config_entry* download_dir = NULL;
	config_entry* nzb_dir = NULL;
	char nzbXsdPath[1024];

	void* managerstate = NULL;

	if ( (max_threads = config_findEntry(cfg, "maxThreads")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing maxthreads!");
		return NULL;
	}

	if ( (max_connect_tries = config_findEntry(cfg, "maxConnectTries")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing maxConnectTries");
		return NULL;
	}

	if ( (max_article_tries = config_findEntry(cfg, "maxArticleTries")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing maxArticleTries");
		return NULL;
	}

	if ( (username = config_findEntry(cfg, "username")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing username");
		return NULL;
	}

	if ( (password = config_findEntry(cfg, "password")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing password");
		return NULL;
	}

	if ( (port = config_findEntry(cfg, "port")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing port");
		return NULL;
	}

	if ( (host = config_findEntry(cfg, "host")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing host");
		return NULL;
	}

	if ( (enable_yenc = config_findEntry(cfg, "enableYEnc")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing enableYEnc");
		return NULL;
	}

	if ( (enable_remote = config_findEntry(cfg, "enableRemoteControl")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing enableRemoteControl");
		return NULL;
	}

	if ( (enable_combine = config_findEntry(cfg, "enableFileCombine")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing enableFileCombine");
		return NULL;
	}

	if ( (remote_port = config_findEntry(cfg, "remoteControlPort")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing remoteControlPort");
		return NULL;
	}

	if ( (download_dir = config_findEntry(cfg, "downloadDir")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing downloadDir");
		return NULL;
	}

	if ( (nzb_dir = config_findEntry(cfg, "nzbDir")) == NULL )
	{
		PRINTERROR("StartDownload::ConfigFile, missing nzbDir");
		return NULL;
	}

	if ( atoi(max_threads->value) <= 0 )
	{
		PRINTERROR("StartDownload::ConfigFile, maxThreads must not be zero or less");
		return NULL;
	}

	if ( atoi(max_article_tries->value) <= 0 )
	{
		PRINTERROR("StartDownload::ConfigFile, maxArticleTries must not be zero or less");
		return NULL;
	}

	if ( atoi(max_connect_tries->value) <= 0 )
	{
		PRINTERROR("StartDownload::ConfigFile, maxConnectTries must not be zero or less");
		return NULL;
	}

	if ( !filesys_itemExists(download_dir->value) )
	{
		PRINTERROR("StartDownload::ConfigFile, Download directory does not exist");
		return NULL;
	}

	strcpy(nzbXsdPath, nzb_dir->value);
	strcat(nzbXsdPath, "nzb.xsd");

	if ( !filesys_itemExists(nzbXsdPath) )
	{
		PRINTERROR("Main::Nzb validation schema does not exist in nzb path");
		exit(1);
	}

	if ( (managerstate = manager_createState(host->value, atoi(port->value), strcmp(enable_remote->value,"1")==0, atoi(remote_port->value))) == NULL )
		return NULL;

	manager_setAuthentication(managerstate, 1);
	manager_setMaxThreads(managerstate, atoi(max_threads->value));
	manager_setUsername(managerstate, username->value);
	manager_setPassword(managerstate, password->value);
	manager_setYEnc(managerstate, strcmp(enable_yenc->value, "1") == 0);
	manager_setMaxConnectionTries(managerstate, atoi(max_connect_tries->value));
	manager_setMaxArticleTries(managerstate, atoi(max_article_tries->value));
	manager_setDownloadPath(managerstate, download_dir->value);
	manager_setNzbPath(managerstate, nzb_dir->value);
	manager_setFileCombine(managerstate, strcmp(enable_combine->value, "1") == 0);

	return managerstate;
}

/**
	Starts scanning directory for nzb files. 
	@param managerstate Pointer to manager
	@returns int indicating success 
*/
int startNzbCheck(void* managerstate, char* dir)
{
	filesys_entry** entries = NULL;

	int count = 0;
	int i =0;

	while ( 1 )
	{
		/* read all file system entries (directories/files) from directory */
		if ( (entries = filesys_readDirectory(dir, &count)) == NULL )
		{
			PRINTERROR("StartNzbCheck::Error reading directory");
			exit(1);
		}

		for ( i=0; i<count; i++ )
		{
			if ( entries[i]->type == FILESYS_FILE )
			{
				int name_len = 0;

				name_len = (int)strlen(entries[i]->name);

				/* extension matches nzb */
				if ( name_len > 4 && stricmp(entries[i]->name+name_len-4, ".nzb") == 0 )
				{
					char path[1024];
#ifdef WIN32
	TCHAR widePath[1024];
#endif

					memset(path, 0, sizeof(path));

					sprintf(path, "%s%s", dir, entries[i]->name);
					
					manager_download(managerstate, path);		

#ifdef WIN32
if ( MultiByteToWideChar(CP_ACP, 0, path, -1, widePath, 1024) == 0 )
{
	PRINTERROR("Main::StartNzbCheck");
	exit(1);
}
DeleteFile(widePath);
#else
	unlink(path);
#endif
					
				}
			}
		}

		/* free the allocated entries */
		for ( i=0; i<count; i++ )
		{
			free(entries[i]);	
		}

		free(entries);

		SLEEP(10);
	}

	
	return 1;
}


